home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / mig / dist / user.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-28  |  46.8 KB  |  1,561 lines

  1. /* 
  2.  * Mach Operating System
  3.  * Copyright (c) 1991,1990 Carnegie Mellon University
  4.  * All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify and distribute this software and its
  7.  * documentation is hereby granted, provided that both the copyright
  8.  * notice and this permission notice appear in all copies of the
  9.  * software, derivative works or modified versions, and any portions
  10.  * thereof, and that both notices appear in supporting documentation.
  11.  * 
  12.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
  13.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15.  * 
  16.  * Carnegie Mellon requests users of this software to return to
  17.  * 
  18.  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  19.  *  School of Computer Science
  20.  *  Carnegie Mellon University
  21.  *  Pittsburgh PA 15213-3890
  22.  * 
  23.  * any improvements or extensions that they make and grant Carnegie the
  24.  * rights to redistribute these changes.
  25.  */
  26. /*
  27.  * HISTORY
  28.  * $Log:    user.c,v $
  29.  * Revision 2.10  92/01/14  16:46:59  rpd
  30.  *     Changed CountInOut code generation, to send the minimum
  31.  *     of the reply msg buffer size and the user's buffer size.
  32.  *     [92/01/13            rpd]
  33.  * 
  34.  *     Fixed WriteExtractArgValue/itIndefinite, in the case when
  35.  *     the data is in-line but doesn't fit.
  36.  *     Fixed Indefinite code generation, to allow short type descriptors.
  37.  *     Added deallocate bit handling to Indefinite code generation.
  38.  *     [92/01/08            rpd]
  39.  * 
  40.  * Revision 2.9  92/01/03  20:30:38  dbg
  41.  *     Redo handling of OUT arrays that are passed in-line or
  42.  *     out-of-line.  Treat more like out-of-line arrays:
  43.  *     user allocates buffer and pointer
  44.  *     fills in pointer with buffer address
  45.  *     passes pointer to stub
  46.  *     stub copies data to *pointer, or changes pointer
  47.  *     User can always use *pointer.
  48.  * 
  49.  *     Change argByReferenceUser to a field in argument_t.
  50.  *     [91/09/04            dbg]
  51.  * 
  52.  * Revision 2.8  91/08/28  11:17:34  jsb
  53.  *     Added MIG_SERVER_DIED.
  54.  *     [91/08/21            rpd]
  55.  *     Removed Camelot and TrapRoutine support.
  56.  *     Changed MsgKind to MsgSeqno.
  57.  *     [91/08/12            rpd]
  58.  * 
  59.  * Revision 2.7  91/07/31  18:11:31  dbg
  60.  *     Allow indefinite-length variable arrays.  They may be copied
  61.  *     either in-line or out-of-line, depending on size.
  62.  * 
  63.  *     Copy variable-length C Strings with mig_strncpy, to combine
  64.  *     'strcpy' and 'strlen' operations.
  65.  * 
  66.  *     New method for advancing request message pointer past
  67.  *     variable-length arguments.  We no longer have to know the order
  68.  *     of variable-length arguments and their count arguments.
  69.  * 
  70.  *     Remove redundant assignments (to msgh_simple, msgh_size) in
  71.  *     generated code.
  72.  *     [91/07/17            dbg]
  73.  * 
  74.  * Revision 2.6  91/06/26  14:39:44  rpd
  75.  *     Removed the dummy user initialization function,
  76.  *     which was kept for backwards-compatibility.
  77.  *     [91/06/26            rpd]
  78.  * 
  79.  * Revision 2.5  91/06/25  10:32:22  rpd
  80.  *     Cast request and reply ports to mach_port_t in KernelUser stubs.
  81.  *     [91/05/27            rpd]
  82.  * 
  83.  *     Changed HeaderFileName to UserHeaderFileName.
  84.  *     Changed WriteVarDecl to WriteUserVarDecl.
  85.  *     [91/05/23            rpd]
  86.  * 
  87.  * Revision 2.4  91/02/05  17:56:20  mrt
  88.  *     Changed to new Mach copyright
  89.  *     [91/02/01  17:56:28  mrt]
  90.  * 
  91.  * Revision 2.3  90/06/19  23:01:20  rpd
  92.  *     Added UserFilePrefix support.
  93.  *     [90/06/03            rpd]
  94.  * 
  95.  * Revision 2.2  90/06/02  15:06:03  rpd
  96.  *     Created for new IPC.
  97.  *     [90/03/26  21:14:40  rpd]
  98.  * 
  99.  * 07-Apr-89  Richard Draves (rpd) at Carnegie-Mellon University
  100.  *    Extensive revamping.  Added polymorphic arguments.
  101.  *    Allow multiple variable-sized inline arguments in messages.
  102.  *
  103.  * 21-Feb-89  David Golub (dbg) at Carnegie-Mellon University
  104.  *    Get name for header file from HeaderFileName, since it can
  105.  *    change.
  106.  *
  107.  *  8-Feb-89  David Golub (dbg) at Carnegie-Mellon University
  108.  *    Added WriteUserIndividual to put each user-side routine in its
  109.  *    own file.
  110.  *
  111.  *  8-Jul-88  Mary Thompson (mrt) at Carnegie-Mellon University
  112.  *    Declared routines to be mig_external instead of extern,
  113.  *    where mig_external is conditionally defined in <subsystem>.h.
  114.  *    The Avalon folks want to define mig_external to be static
  115.  *    in their compilations because they inlcude the User.c code in
  116.  *    their programs.
  117.  *
  118.  * 23-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
  119.  *    Changed the include of camelot_types.h to cam/camelot_types.h
  120.  *
  121.  * 19-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
  122.  *    Added comments for each routine. Called WriteMsgError
  123.  *    for MIG_ARRAY_TOO_LARGE errors.
  124.  *
  125.  * 19-Jan-88  David Golub (dbg) at Carnegie-Mellon University
  126.  *    Change variable-length inline array declarations to use
  127.  *    maximum size specified to Mig.  Make message variable
  128.  *    length if the last item in the message is variable-length
  129.  *    and inline.  Use argMultiplier field to convert between
  130.  *    argument and IPC element counts.
  131.  *
  132.  * 19-Jan-88  Mary Thompson (mrt) at Carnegie-Mellon University
  133.  *    In WriteInitRoutine changed reference from reply_port; to reply_port++;
  134.  *    for lint code.
  135.  *
  136.  * 17-Jan-88  David Detlefs (dld) at Carnegie-Mellon University
  137.  *    Modified to produce C++ compatible code via #ifdefs.
  138.  *    All changes have to do with argument declarations.
  139.  *
  140.  * 16-Nov-87  David Golub (dbg) at Carnegie-Mellon University
  141.  *    Handle variable-length inline arrays.
  142.  *
  143.  * 22-Oct-87  Mary Thompson (mrt) at Carnegie-Mellon University
  144.  *     Added a reference to rep_port in the InitRoutine
  145.  *    with an ifdef lint conditional.
  146.  *
  147.  * 22-Sep-87  Mary Thompson (mrt) at Carnegie-Mellon University
  148.  *    Fixed check for TransId to be a not equal test
  149.  *    rather than an equal test.
  150.  *
  151.  *  2-Sep-87  Mary Thompson (mrt) at Carnegie-Mellon University
  152.  *    Changed WriteCheckIdentity to check TransId instead
  153.  *    of msgh_id for a returned camelot reply
  154.  *
  155.  * 24-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  156.  *    Added a  LINTLIBRARY  line to keep lint
  157.  *    from complaining about routines that are not used.
  158.  *
  159.  * 21-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  160.  *    Added Flag parameter to WritePackMsgType.
  161.  *
  162.  * 12-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  163.  *    Made various camelot changes: include of camelot_types.h
  164.  *    Check for death_pill before correct msg-id.
  165.  *
  166.  * 10-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  167.  *    Renamed get_reply_port and dealloc_reply_port to
  168.  *    mig_get_reply_port and mig_dealloc_reply_port.
  169.  *    Fixed WriteRequestHead to handle MsgType parameter.
  170.  *
  171.  *  3-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  172.  *    Fixed to generate code that is the same for multi-threaded and
  173.  *    single threaded use. Gets reply port from library routine
  174.  *    get_reply_port and deallocates with routine
  175.  *    dealloc_reply_port. Removed all routines in mig interface code
  176.  *    to keep track of the reply port. The init routine still exists
  177.  *    but does nothing.
  178.  * 
  179.  * 29-Jul_87  Mary Thompson (mrt) at Carnegie-Mellon University
  180.  *     Fixed call to WriteVarDecl to use correspond to
  181.  *    the changes that were made in that routine.
  182.  *
  183.  * 16-Jul-87  Robert Sansom (rds) at Carnegie Mellon University
  184.  *    Added write of MsgType to WriteSetMsgTypeRoutine.
  185.  *
  186.  *  8-Jun-87  Mary Thompson (mrt) at Carnegie-Mellon University
  187.  *    Removed #include of sys/types.h from WriteIncludes.
  188.  *    Changed the KERNEL include from ../h to sys/
  189.  *    Removed extern from WriteUser to make hi-c happy
  190.  *
  191.  * 28-May-87  Richard Draves (rpd) at Carnegie-Mellon University
  192.  *    Created.
  193.  */
  194.  
  195. #include <assert.h>
  196.  
  197. #include <mach/message.h>
  198. #include "write.h"
  199. #include "error.h"
  200. #include "utils.h"
  201. #include "global.h"
  202.  
  203. /*************************************************************
  204.  *    Writes the standard includes. The subsystem specific
  205.  *    includes  are in <SubsystemName>.h and writen by
  206.  *    header:WriteHeader. Called by WriteProlog.
  207.  *************************************************************/
  208. static void
  209. WriteIncludes(file)
  210.     FILE *file;
  211. {
  212.     if (IsKernelServer)
  213.     {
  214.     /*
  215.      *    We want to get the user-side definitions of types
  216.      *    like task_t, ipc_space_t, etc. in mach/mach_types.h.
  217.      */
  218.  
  219.     fprintf(file, "#undef\tKERNEL\n");
  220.  
  221.     if (InternalHeaderFileName != strNULL)
  222.     {
  223.         register char *cp;
  224.  
  225.         /* Strip any leading path from InternalHeaderFileName. */
  226.         cp = rindex(InternalHeaderFileName, '/');
  227.         if (cp == 0)
  228.         cp = InternalHeaderFileName;
  229.         else
  230.         cp++;    /* skip '/' */
  231.         fprintf(file, "#include \"%s\"\n", cp);
  232.     }
  233.     }
  234.  
  235.     if (UserHeaderFileName != strNULL)
  236.     {
  237.     register char *cp;
  238.  
  239.     /* Strip any leading path from UserHeaderFileName. */
  240.     cp = rindex(UserHeaderFileName, '/');
  241.     if (cp == 0)
  242.         cp = UserHeaderFileName;
  243.     else
  244.         cp++;    /* skip '/' */
  245.     fprintf(file, "#include \"%s\"\n", cp);
  246.     }
  247.  
  248.     fprintf(file, "#define EXPORT_BOOLEAN\n");
  249.     fprintf(file, "#include <mach/boolean.h>\n");
  250.     fprintf(file, "#include <mach/kern_return.h>\n");
  251.     fprintf(file, "#include <mach/message.h>\n");
  252.     fprintf(file, "#include <mach/notify.h>\n");
  253.     fprintf(file, "#include <mach/mach_types.h>\n");
  254.     fprintf(file, "#include <mach/mig_errors.h>\n");
  255.     fprintf(file, "#include <mach/msg_type.h>\n");
  256.     if (!IsKernelServer)
  257.     {
  258.     /* note KERNEL is undefined when IsKernelServer */
  259.     fprintf(file, "#ifndef\tKERNEL\n");
  260.     fprintf(file, "#include <strings.h>\n");
  261.     fprintf(file, "#endif\tKERNEL\n");
  262.     }
  263.     fprintf(file, "/* LINTLIBRARY */\n");
  264.     fprintf(file, "\n");
  265.     fprintf(file, "extern mach_port_t mig_get_reply_port();\n");
  266.     fprintf(file, "extern void mig_dealloc_reply_port();\n");
  267.     fprintf(file, "\n");
  268. }
  269.  
  270. static void
  271. WriteGlobalDecls(file)
  272.     FILE *file;
  273. {
  274.     if (RCSId != strNULL)
  275.     WriteRCSDecl(file, strconcat(SubsystemName, "_user"), RCSId);
  276.  
  277.     fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
  278.     fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
  279.     fprintf(file, "\n");
  280. }
  281.  
  282. /*************************************************************
  283.  *    Writes the standard #includes, #defines, and
  284.  *    RCS declaration. Called by WriteUser.
  285.  *************************************************************/
  286. static void
  287. WriteProlog(file)
  288.     FILE *file;
  289. {
  290.     WriteIncludes(file);
  291.     WriteBogusDefines(file);
  292.     WriteGlobalDecls(file);
  293. }
  294.  
  295. /*ARGSUSED*/
  296. static void
  297. WriteEpilog(file)
  298.     FILE *file;
  299. {
  300. }
  301.  
  302. static string_t
  303. WriteHeaderPortType(arg)
  304.     argument_t *arg;
  305. {
  306.     if (arg->argType->itInName == MACH_MSG_TYPE_POLYMORPHIC)
  307.     return arg->argPoly->argVarName;
  308.     else
  309.     return arg->argType->itInNameStr;
  310. }
  311.  
  312. static void
  313. WriteRequestHead(file, rt)
  314.     FILE *file;
  315.     routine_t *rt;
  316. {
  317.     if (rt->rtMaxRequestPos > 0)
  318.     fprintf(file, "\tInP = &Mess.In;\n");
  319.  
  320.     if (rt->rtSimpleFixedRequest) {
  321.     fprintf(file, "\tInP->Head.msgh_bits =");
  322.     if (!rt->rtSimpleSendRequest)
  323.         fprintf(file, " MACH_MSGH_BITS_COMPLEX|");
  324.     fprintf(file, "\n");
  325.     fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s);\n",
  326.         WriteHeaderPortType(rt->rtRequestPort),
  327.         WriteHeaderPortType(rt->rtReplyPort));
  328.     } else {
  329.     fprintf(file, "\tInP->Head.msgh_bits = msgh_simple ?\n");
  330.     fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s) :\n",
  331.         WriteHeaderPortType(rt->rtRequestPort),
  332.         WriteHeaderPortType(rt->rtReplyPort));
  333.     fprintf(file, "\t\t(MACH_MSGH_BITS_COMPLEX|\n");
  334.     fprintf(file, "\t\t MACH_MSGH_BITS(%s, %s));\n",
  335.         WriteHeaderPortType(rt->rtRequestPort),
  336.         WriteHeaderPortType(rt->rtReplyPort));
  337.     }
  338.  
  339.     fprintf(file, "\t/* msgh_size passed as argument */\n");
  340.  
  341.     /*
  342.      *    KernelUser stubs need to cast the request and reply ports
  343.      *    from ipc_port_t to mach_port_t.
  344.      */
  345.  
  346.     if (IsKernelUser)
  347.     fprintf(file, "\tInP->%s = (mach_port_t) %s;\n",
  348.         rt->rtRequestPort->argMsgField,
  349.         rt->rtRequestPort->argVarName);
  350.     else
  351.     fprintf(file, "\tInP->%s = %s;\n",
  352.         rt->rtRequestPort->argMsgField,
  353.         rt->rtRequestPort->argVarName);
  354.  
  355.     if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) {
  356.     if (IsKernelUser)
  357.         fprintf(file, "\tInP->%s = (mach_port_t) %s;\n",
  358.             rt->rtReplyPort->argMsgField,
  359.             rt->rtReplyPort->argVarName);
  360.     else
  361.         fprintf(file, "\tInP->%s = %s;\n",
  362.             rt->rtReplyPort->argMsgField,
  363.             rt->rtReplyPort->argVarName);
  364.     } else if (rt->rtOneWay || IsKernelUser)
  365.     fprintf(file, "\tInP->%s = MACH_PORT_NULL;\n",
  366.         rt->rtReplyPort->argMsgField);
  367.     else
  368.     fprintf(file, "\tInP->%s = mig_get_reply_port();\n",
  369.         rt->rtReplyPort->argMsgField);
  370.  
  371.     fprintf(file, "\tInP->Head.msgh_seqno = 0;\n");
  372.     fprintf(file, "\tInP->Head.msgh_id = %d;\n",
  373.         rt->rtNumber + SubsystemBase);
  374. }
  375.  
  376. /*************************************************************
  377.  *  Writes declarations for the message types, variables
  378.  *  and return  variable if needed. Called by WriteRoutine.
  379.  *************************************************************/
  380. static void
  381. WriteVarDecls(file, rt)
  382.     FILE *file;
  383.     routine_t *rt;
  384. {
  385.     fprintf(file, "\tunion {\n");
  386.     fprintf(file, "\t\tRequest In;\n");
  387.     if (!rt->rtOneWay)
  388.     fprintf(file, "\t\tReply Out;\n");
  389.     fprintf(file, "\t} Mess;\n");
  390.     fprintf(file, "\n");
  391.  
  392.     fprintf(file, "\tregister Request *InP = &Mess.In;\n");
  393.     if (!rt->rtOneWay)
  394.     fprintf(file, "\tregister Reply *OutP = &Mess.Out;\n");
  395.     fprintf(file, "\n");
  396.  
  397.     if (!rt->rtOneWay || rt->rtProcedure)
  398.     fprintf(file, "\tmach_msg_return_t msg_result;\n");
  399.  
  400.     if (!rt->rtSimpleFixedRequest)
  401.     fprintf(file, "\tboolean_t msgh_simple = %s;\n",
  402.         strbool(rt->rtSimpleSendRequest));
  403.     else if (!rt->rtOneWay &&
  404.          !(rt->rtSimpleCheckReply && rt->rtSimpleReceiveReply)) {
  405.     fprintf(file, "#if\tTypeCheck\n");
  406.     fprintf(file, "\tboolean_t msgh_simple;\n");
  407.     fprintf(file, "#endif\tTypeCheck\n");
  408.     }
  409.  
  410.     if (rt->rtNumRequestVar > 0)
  411.     fprintf(file, "\tunsigned int msgh_size;\n");
  412.     else if (!rt->rtOneWay && !rt->rtNoReplyArgs)
  413.     {
  414.     fprintf(file, "#if\tTypeCheck\n");
  415.     fprintf(file, "\tunsigned int msgh_size;\n");
  416.     fprintf(file, "#endif\tTypeCheck\n");
  417.     }
  418.  
  419.     /* if either request or reply is variable, we need msgh_size_delta */
  420.     if ((rt->rtMaxRequestPos > 0) ||
  421.     (rt->rtMaxReplyPos > 0))
  422.     fprintf(file, "\tunsigned int msgh_size_delta;\n");
  423.  
  424.     fprintf(file, "\n");
  425. }
  426.  
  427. /*************************************************************
  428.  *  Writes code to call the user provided error procedure
  429.  *  when a MIG error occurs. Called by WriteMsgSend, 
  430.  *  WriteMsgCheckReceive, WriteMsgSendReceive, WriteCheckIdentity,
  431.  *  WriteRetCodeCheck, WriteTypeCheck, WritePackArgValue.
  432.  *************************************************************/
  433. static void
  434. WriteMsgError(file, rt, error)
  435.     FILE *file;
  436.     routine_t *rt;
  437.     char *error;
  438. {
  439.     if (rt->rtProcedure)
  440.     fprintf(file, "\t\t{ %s(%s); return; }\n", rt->rtErrorName, error);
  441.     else if (rt->rtReturn != rt->rtRetCode)
  442.     {
  443.     fprintf(file, "\t\t{ %s(%s); ", rt->rtErrorName, error);
  444.     if (rt->rtNumReplyVar > 0)
  445.         fprintf(file, "OutP = &Mess.Out; ");
  446.     fprintf(file, "return OutP->%s; }\n", rt->rtReturn->argMsgField);
  447.     }
  448.     else
  449.     fprintf(file, "\t\treturn %s;\n", error);
  450. }
  451.  
  452. /*************************************************************
  453.  *   Writes the send call when there is to be no subsequent
  454.  *   receive. Called by WriteRoutine for SimpleProcedures
  455.  *   or SimpleRoutines
  456.  *************************************************************/
  457. static void
  458. WriteMsgSend(file, rt)
  459.     FILE *file;
  460.     routine_t *rt;
  461. {
  462.     char *SendSize = (rt->rtNumRequestVar == 0)
  463.             ? "sizeof(Request)"
  464.             : "msgh_size";
  465.  
  466.     char *MsgResult = (rt->rtProcedure)
  467.             ? "msg_result ="
  468.             : "return";
  469.  
  470.     if (IsKernelUser)
  471.     {
  472.     fprintf(file, "\t%s mach_msg_send_from_kernel(", MsgResult);
  473.     fprintf(file, "&InP->Head, %s);\n", SendSize);
  474.     }
  475.     else
  476.     {
  477.     fprintf(file, "\t%s mach_msg(&InP->Head, MACH_SEND_MSG|%s, %s, 0,",
  478.         MsgResult,
  479.         rt->rtMsgOption->argVarName,
  480.         SendSize);
  481.     fprintf(file,
  482.         " MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n"
  483.         );
  484.     }
  485.  
  486.     if (rt->rtProcedure)
  487.     {
  488.     fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n");
  489.     WriteMsgError(file, rt, "msg_result");
  490.     }
  491. }
  492.  
  493. /*************************************************************
  494.  *  Writes to code to check for error returns from receive.
  495.  *  Called by WriteMsgSendReceive and WriteMsgRPC
  496.  *************************************************************/
  497. static void
  498. WriteMsgCheckReceive(file, rt, success)
  499.     FILE *file;
  500.     routine_t *rt;
  501.     char *success;
  502. {
  503.     fprintf(file, "\tif (msg_result != %s) {\n", success);
  504.     if (!akCheck(rt->rtReplyPort->argKind, akbUserArg) && !IsKernelUser)
  505.     {
  506.     /* If we aren't using a user-supplied reply port, then
  507.        deallocate the reply port when it is invalid or
  508.        for TIMED_OUT errors. */
  509.  
  510.     fprintf(file, "\t\tif ((msg_result == MACH_SEND_INVALID_REPLY) ||\n");
  511.     if (rt->rtWaitTime != argNULL)
  512.         fprintf(file, "\t\t    (msg_result == MACH_RCV_TIMED_OUT) ||\n");
  513.     fprintf(file, "\t\t    (msg_result == MACH_RCV_INVALID_NAME))\n");
  514.     fprintf(file, "\t\t\tmig_dealloc_reply_port();\n");
  515.     }
  516.     WriteMsgError(file, rt, "msg_result");
  517.     fprintf(file, "\t}\n");
  518. }
  519.  
  520. /*************************************************************
  521.  *  Writes the send and receive calls and code to check
  522.  *  for errors. Normally the rpc code is generated instead
  523.  *  although, the subsytem can be compiled with the -R option
  524.  *  which will cause this code to be generated. Called by
  525.  *  WriteRoutine if UseMsgRPC option is false.
  526.  *************************************************************/
  527. static void
  528. WriteMsgSendReceive(file, rt)
  529.     FILE *file;
  530.     routine_t *rt;
  531. {
  532.     char *SendSize = (rt->rtNumRequestVar == 0)
  533.             ? "sizeof(Request)"
  534.             : "msgh_size";
  535.  
  536.     fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|%s, %s, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n",
  537.         rt->rtMsgOption->argVarName,
  538.         SendSize);
  539.  
  540.     fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n");
  541.     WriteMsgError(file, rt, "msg_result");
  542.     fprintf(file, "\n");
  543.  
  544.     fprintf(file, "\tmsg_result = mach_msg(&OutP->Head, MACH_RCV_MSG|%s%s, 0, sizeof(Reply), InP->Head.msgh_local_port, %s, MACH_PORT_NULL);\n",
  545.         rt->rtMsgOption->argVarName,
  546.         rt->rtWaitTime != argNULL ? "|MACH_RCV_TIMEOUT" : "",
  547.         rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
  548.     WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
  549.     fprintf(file, "\n");
  550. }
  551.  
  552. static void
  553. WriteMsgReceive(file, rt)
  554.     FILE *file;
  555.     routine_t *rt;
  556. {
  557.     fprintf(file, "\tmsg_result = mach_msg(&OutP->Head, MACH_RCV_MSG|%s%s, 0, sizeof(Reply), %s, %s, MACH_PORT_NULL);\n",
  558.         rt->rtMsgOption->argVarName,
  559.         rt->rtWaitTime != argNULL ? "|MACH_RCV_TIMEOUT" : "",
  560.         rt->rtReplyPort->argVarName,
  561.         rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
  562.     WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
  563.     fprintf(file, "\n");
  564. }
  565.  
  566. /*************************************************************
  567.  *  Writes the rpc call and the code to check for errors.
  568.  *  This is the default code to be generated. Called by WriteRoutine
  569.  *  for all routine types except SimpleProcedure and SimpleRoutine.
  570.  *************************************************************/
  571. static void
  572. WriteMsgRPC(file, rt)
  573.     FILE *file;
  574.     routine_t *rt;
  575. {
  576.     char *SendSize = (rt->rtNumRequestVar == 0)
  577.             ? "sizeof(Request)"
  578.             : "msgh_size";
  579.  
  580.     if (IsKernelUser)
  581.     fprintf(file, "\tmsg_result = mach_msg_rpc_from_kernel(&InP->Head, %s, sizeof(Reply));\n", SendSize);
  582.     else
  583.     fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|%s%s, %s, sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL);\n",
  584.         rt->rtMsgOption->argVarName,
  585.         rt->rtWaitTime != argNULL ? "|MACH_RCV_TIMEOUT" : "",
  586.         SendSize,
  587.         rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
  588.     WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
  589.     fprintf(file, "\n");
  590. }
  591.  
  592. /*************************************************************
  593.  *   Sets the correct value of the dealloc flag and calls
  594.  *   Utils:WritePackMsgType to fill in the ipc msg type word(s)
  595.  *   in the request message. Called by WriteRoutine for each
  596.  *   argument that is to be sent in the request message.
  597.  *************************************************************/
  598. static void
  599. WritePackArgType(file, arg)
  600.     FILE *file;
  601.     argument_t *arg;
  602. {
  603.     WritePackMsgType(file, arg->argType,
  604.              arg->argType->itIndefinite ? d_NO : arg->argDeallocate,
  605.              arg->argLongForm, TRUE,
  606.              "InP->%s", "%s", arg->argTTName);
  607.     fprintf(file, "\n");
  608. }
  609.  
  610. /*************************************************************
  611.  *  Writes code to copy an argument into the request message.  
  612.  *  Called by WriteRoutine for each argument that is to placed
  613.  *  in the request message.
  614.  *************************************************************/
  615. static void
  616. WritePackArgValue(file, arg)
  617.     FILE *file;
  618.     register argument_t *arg;
  619. {
  620.     register ipc_type_t *it = arg->argType;
  621.     register char *ref = arg->argByReferenceUser ? "*" : "";
  622.  
  623.     if (it->itInLine && it->itVarArray) {
  624.  
  625.     if (it->itString) {
  626.         /*
  627.          *    Copy variable-size C string with mig_strncpy.
  628.          *    Save the string length (+ 1 for trailing 0)
  629.          *    in the argument`s count field.
  630.          */
  631.         fprintf(file,
  632.         "\tInP->%s = mig_strncpy(InP->%s, %s, %d);\n",
  633.         arg->argCount->argMsgField,
  634.         arg->argMsgField,
  635.         arg->argVarName,
  636.         it->itNumber);
  637.     }
  638.     else {
  639.  
  640.         /*
  641.          *    Copy in variable-size inline array with bcopy,
  642.          *    after checking that number of elements doesn`t
  643.          *    exceed declared maximum.
  644.          */
  645.         register argument_t *count = arg->argCount;
  646.         register char *countRef = count->argByReferenceUser ? "*" : "";
  647.         register ipc_type_t *btype = it->itElement;
  648.  
  649.         /* Note btype->itNumber == count->argMultiplier */
  650.  
  651.         fprintf(file, "\tif (%s%s > %d) {\n",
  652.         countRef, count->argVarName,
  653.         it->itNumber/btype->itNumber);
  654.         if (it->itIndefinite) {
  655.         fprintf(file, "\t\tInP->%s%s.msgt_inline = FALSE;\n",
  656.             arg->argTTName,
  657.             arg->argLongForm ? ".msgtl_header" : "");
  658.         if (arg->argDeallocate == d_YES)
  659.             fprintf(file, "\t\tInP->%s%s.msgt_deallocate = TRUE;\n",
  660.                 arg->argTTName,
  661.                 arg->argLongForm ? ".msgtl_header" : "");
  662.         else if (arg->argDeallocate == d_MAYBE)
  663.             fprintf(file, "\t\tInP->%s%s.msgt_deallocate = %s%s;\n",
  664.                 arg->argTTName,
  665.                 arg->argLongForm ? ".msgtl_header" : "",
  666.                 arg->argDealloc->argByReferenceUser ? "*" : "",
  667.                 arg->argDealloc->argVarName);
  668.         fprintf(file, "\t\t*((%s **)InP->%s) = %s%s;\n",
  669.             FetchUserType(btype),
  670.             arg->argMsgField,
  671.             ref, arg->argVarName);
  672.         if (!arg->argRoutine->rtSimpleFixedRequest)
  673.             fprintf(file, "\t\tmsgh_simple = FALSE;\n");
  674.         }
  675.         else
  676.         WriteMsgError(file, arg->argRoutine, "MIG_ARRAY_TOO_LARGE");
  677.  
  678.         fprintf(file, "\t}\n\telse {\n");
  679.  
  680.         fprintf(file, "\t\tbcopy((char *) %s%s, (char *) InP->%s, ",
  681.         ref, arg->argVarName, arg->argMsgField);
  682.         if (btype->itTypeSize > 1)
  683.         fprintf(file, "%d * ", btype->itTypeSize);
  684.         fprintf(file, "%s%s);\n",
  685.         countRef, count->argVarName);
  686.         fprintf(file, "\t}\n");
  687.     }
  688.     }
  689.     else if (arg->argMultiplier > 1)
  690.     WriteCopyType(file, it, "InP->%s", "/* %s */ %d * %s%s",
  691.               arg->argMsgField, arg->argMultiplier,
  692.               ref, arg->argVarName);
  693.     else
  694.     WriteCopyType(file, it, "InP->%s", "/* %s */ %s%s",
  695.               arg->argMsgField, ref, arg->argVarName);
  696.     fprintf(file, "\n");
  697. }
  698.  
  699. static void
  700. WriteAdjustMsgSimple(file, arg)
  701.     FILE *file;
  702.     register argument_t *arg;
  703. {
  704.     if (!arg->argRoutine->rtSimpleFixedRequest)
  705.     {
  706.     register char *ref = arg->argByReferenceUser ? "*" : "";
  707.  
  708.     fprintf(file, "\tif (MACH_MSG_TYPE_PORT_ANY(%s%s))\n",
  709.         ref, arg->argVarName);
  710.     fprintf(file, "\t\tmsgh_simple = FALSE;\n");
  711.     fprintf(file, "\n");
  712.     }
  713. }
  714.  
  715. /*
  716.  * Calculate the size of a variable-length message field.
  717.  */
  718. static void
  719. WriteArgSize(file, arg)
  720.     FILE *file;
  721.     register argument_t *arg;
  722. {
  723.     register ipc_type_t *ptype = arg->argType;
  724.     register int bsize = ptype->itElement->itTypeSize;
  725.     register argument_t *count = arg->argCount;
  726.  
  727.     if (ptype->itIndefinite) {
  728.     /*
  729.      *    Check descriptor.  If out-of-line, use standard size.
  730.      */
  731.     fprintf(file, "(InP->%s%s.msgt_inline) ? ",
  732.         arg->argTTName, arg->argLongForm ? ".msgtl_header" : "");
  733.     }
  734.     if (bsize > 1)
  735.     fprintf(file, "%d * ", bsize);
  736.     if (ptype->itString)
  737.     /* get count from descriptor in message */
  738.     fprintf(file, "InP->%s", count->argMsgField);
  739.     else
  740.     /* get count from argument */
  741.     fprintf(file, "%s%s",
  742.         count->argByReferenceUser ? "*" : "",
  743.         count->argVarName);
  744.  
  745.     /*
  746.      * If the base type size is not a multiple of sizeof(int) [4],
  747.      * we have to round up.
  748.      */
  749.     if (bsize % 4 != 0)
  750.     fprintf(file, " + 3 & ~3");
  751.  
  752.     if (ptype->itIndefinite) {
  753.     fprintf(file, " : sizeof(%s *)",
  754.         FetchUserType(ptype->itElement));
  755.     }
  756. }
  757.  
  758. /*
  759.  * Adjust message size and advance request pointer.
  760.  * Called after packing a variable-length argument that
  761.  * has more arguments following.
  762.  */
  763. static void
  764. WriteAdjustMsgSize(file, arg)
  765.     FILE *file;
  766.     register argument_t *arg;
  767. {
  768.     register ipc_type_t *ptype = arg->argType;
  769.  
  770.     /* There are more In arguments.  We need to adjust msgh_size
  771.        and advance InP, so we save the size of the current field
  772.        in msgh_size_delta. */
  773.  
  774.     fprintf(file, "\tmsgh_size_delta = ");
  775.     WriteArgSize(file, arg);
  776.     fprintf(file, ";\n");
  777.  
  778.     if (arg->argRequestPos == 0)
  779.     /* First variable-length argument.  The previous msgh_size value
  780.        is the minimum request size. */
  781.  
  782.     fprintf(file, "\tmsgh_size = %d + msgh_size_delta;\n",
  783.         arg->argRoutine->rtRequestSize);
  784.     else
  785.     fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
  786.  
  787.     fprintf(file,
  788.     "\tInP = (Request *) ((char *) InP + msgh_size_delta - %d);\n",
  789.     ptype->itTypeSize + ptype->itPadSize);
  790. }
  791.  
  792. /*
  793.  * Calculate the size of the message.  Called after the
  794.  * last argument has been packed.
  795.  */
  796. static void
  797. WriteFinishMsgSize(file, arg)
  798.     FILE *file;
  799.     register argument_t *arg;
  800. {
  801.     /* No more In arguments.  If this is the only variable In
  802.        argument, the previous msgh_size value is the minimum
  803.        request size. */
  804.  
  805.     if (arg->argRequestPos == 0) {
  806.     fprintf(file, "\tmsgh_size = %d + (",
  807.             arg->argRoutine->rtRequestSize);
  808.     WriteArgSize(file, arg);
  809.     fprintf(file, ");\n");
  810.     }
  811.     else {
  812.         fprintf(file, "\tmsgh_size += ");
  813.     WriteArgSize(file, arg);
  814.         fprintf(file, ";\n");
  815.     }
  816. }
  817.  
  818. static void
  819. WriteInitializeCount(file, arg)
  820.     FILE *file;
  821.     register argument_t *arg;
  822. {
  823.     register ipc_type_t *ptype = arg->argCInOut->argParent->argType;
  824.     register ipc_type_t *btype = ptype->itElement;
  825.  
  826.     fprintf(file, "\tif (%s%s < %d)\n",
  827.         arg->argByReferenceUser ? "*" : "",
  828.         arg->argVarName,
  829.         ptype->itNumber/btype->itNumber);
  830.     fprintf(file, "\t\tInP->%s = %s%s;\n",
  831.         arg->argMsgField,
  832.         arg->argByReferenceUser ? "*" : "",
  833.         arg->argVarName);
  834.     fprintf(file, "\telse\n");
  835.     fprintf(file, "\t\tInP->%s = %d;\n",
  836.         arg->argMsgField, ptype->itNumber/btype->itNumber);
  837.     fprintf(file, "\n");
  838. }
  839.  
  840. /*
  841.  * Called for every argument.  Responsible for packing that
  842.  * argument into the request message.
  843.  */
  844. static void
  845. WritePackArg(file, arg)
  846.     FILE *file;
  847.     register argument_t *arg;
  848. {
  849.     if (akCheck(arg->argKind, akbRequest))
  850.     WritePackArgType(file, arg);
  851.  
  852.     if ((akIdent(arg->argKind) == akePoly) &&
  853.     akCheck(arg->argKind, akbSendSnd))
  854.     WriteAdjustMsgSimple(file, arg);
  855.  
  856.     if ((akIdent(arg->argKind) == akeCountInOut) &&
  857.     akCheck(arg->argKind, akbSendSnd))
  858.     WriteInitializeCount(file, arg);
  859.     else if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody))
  860.     WritePackArgValue(file, arg);
  861. }
  862.  
  863. /*
  864.  * Generate code to fill in all of the request arguments and their
  865.  * message types.
  866.  */
  867. WriteRequestArgs(file, rt)
  868.     FILE *file;
  869.     register routine_t *rt;
  870. {
  871.     register argument_t *arg;
  872.     register argument_t *lastVarArg;
  873.  
  874.     lastVarArg = argNULL;
  875.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
  876.  
  877.     /*
  878.      * Adjust message size and advance message pointer if
  879.      * the last request argument was variable-length and the
  880.      * request position will change.
  881.      */
  882.     if (lastVarArg != argNULL &&
  883.         lastVarArg->argRequestPos < arg->argRequestPos)
  884.     {
  885.         WriteAdjustMsgSize(file, lastVarArg);
  886.         lastVarArg = argNULL;
  887.     }
  888.  
  889.     /*
  890.      * Copy the argument
  891.      */
  892.     WritePackArg(file, arg);
  893.  
  894.     /*
  895.      * Remember whether this was variable-length.
  896.      */
  897.     if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody|akbVariable))
  898.         lastVarArg = arg;
  899.     }
  900.  
  901.     /*
  902.      * Finish the message size.
  903.      */
  904.     if (lastVarArg != argNULL)
  905.     WriteFinishMsgSize(file, lastVarArg);
  906. }
  907.  
  908. /*************************************************************
  909.  *  Writes code to check that the return msgh_id is correct and that
  910.  *  the size of the return message is correct. Called by
  911.  *  WriteRoutine.
  912.  *************************************************************/
  913. static void
  914. WriteCheckIdentity(file, rt)
  915.     FILE *file;
  916.     routine_t *rt;
  917. {
  918.     fprintf(file, "\tif (OutP->Head.msgh_id != %d) {\n",
  919.         rt->rtNumber + SubsystemBase + 100);
  920.     fprintf(file, "\t\tif (OutP->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n");
  921.     WriteMsgError(file, rt, "MIG_SERVER_DIED");
  922.     fprintf(file, "\t\telse\n");
  923.     WriteMsgError(file, rt, "MIG_REPLY_MISMATCH");
  924.     fprintf(file, "\t}\n");
  925.     fprintf(file, "\n");
  926.     fprintf(file, "#if\tTypeCheck\n");
  927.  
  928.     if (rt->rtSimpleCheckReply && rt->rtSimpleReceiveReply)
  929.     {
  930.     /* Expecting a simple message.  We can factor out the check for
  931.        a simple message, since the error reply message is also simple.
  932.        */
  933.  
  934.     if (!rt->rtNoReplyArgs)
  935.         fprintf(file, "\tmsgh_size = OutP->Head.msgh_size;\n\n");
  936.  
  937.     fprintf(file,
  938.         "\tif ((OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
  939.     if (rt->rtNoReplyArgs)
  940.         fprintf(file, "\t    (OutP->Head.msgh_size != %d))\n",
  941.             rt->rtReplySize);
  942.     else {
  943.         fprintf(file, "\t    ((msgh_size %s %d) &&\n",
  944.         (rt->rtNumReplyVar > 0) ? "<" : "!=",
  945.         rt->rtReplySize);
  946.         fprintf(file, "\t     ((msgh_size != sizeof(mig_reply_header_t)) ||\n");
  947.         fprintf(file, "\t      (OutP->RetCode == KERN_SUCCESS))))\n");
  948.     }
  949.     }
  950.     else {
  951.     /* Expecting a complex message, or may vary at run time. */
  952.  
  953.     fprintf(file, "\tmsgh_size = OutP->Head.msgh_size;\n");
  954.     fprintf(file, "\tmsgh_simple = !(OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n");
  955.     fprintf(file, "\n");
  956.  
  957.     fprintf(file, "\tif (((msgh_size %s %d)",
  958.         (rt->rtNumReplyVar > 0) ? "<" : "!=",
  959.         rt->rtReplySize);
  960.  
  961.     if (rt->rtSimpleCheckReply)
  962.         /* if rtSimpleReceiveReply was true, then we would have
  963.            executed the code above.  So we know that the message
  964.            is complex. */
  965.         fprintf(file, " || msgh_simple");
  966.     fprintf(file, ") &&\n");
  967.  
  968.     fprintf(file, "\t    ((msgh_size != sizeof(mig_reply_header_t)) ||\n");
  969.     fprintf(file, "\t     !msgh_simple ||\n");
  970.     fprintf(file, "\t     (OutP->RetCode == KERN_SUCCESS)))\n");
  971.     }
  972.     WriteMsgError(file, rt, "MIG_TYPE_ERROR");
  973.     fprintf(file, "#endif\tTypeCheck\n");
  974.     fprintf(file, "\n");
  975. }
  976.  
  977. /*************************************************************
  978.  *  Write code to generate error handling code if the RetCode
  979.  *  argument of a Routine is not KERN_SUCCESS.
  980.  *************************************************************/
  981. static void
  982. WriteRetCodeCheck(file, rt)
  983.     FILE *file;
  984.     routine_t *rt;
  985. {
  986.     fprintf(file, "\tif (OutP->RetCode != KERN_SUCCESS)\n");
  987.     WriteMsgError(file, rt, "OutP->RetCode");
  988.     fprintf(file, "\n");
  989. }
  990.  
  991. /*************************************************************
  992.  *  Writes code to check that the type of each of the arguments
  993.  *  in the reply message is what is expected. Called by 
  994.  *  WriteRoutine for each argument in the reply message.
  995.  *************************************************************/
  996. static void
  997. WriteTypeCheck(file, arg)
  998.     FILE *file;
  999.     register argument_t *arg;
  1000. {
  1001.     register ipc_type_t *it = arg->argType;
  1002.     register routine_t *rt = arg->argRoutine;
  1003.  
  1004.     fprintf(file, "#if\tTypeCheck\n");
  1005.     if (akCheck(arg->argKind, akbReplyQC))
  1006.     {
  1007.     fprintf(file, "#if\tUseStaticMsgType\n");
  1008.     fprintf(file, "\tif (* (int *) &OutP->%s != * (int *) &%sCheck)\n",
  1009.         arg->argTTName, arg->argVarName);
  1010.     fprintf(file, "#else\tUseStaticMsgType\n");
  1011.     }
  1012.     fprintf(file, "\tif (");
  1013.     if (!it->itIndefinite) {
  1014.     fprintf(file, "(OutP->%s%s.msgt_inline != %s) ||\n\t    ",
  1015.         arg->argTTName,
  1016.         arg->argLongForm ? ".msgtl_header" : "",
  1017.         strbool(it->itInLine));
  1018.     }
  1019.     fprintf(file, "(OutP->%s%s.msgt_longform != %s) ||\n",
  1020.         arg->argTTName,
  1021.         arg->argLongForm ? ".msgtl_header" : "",
  1022.         strbool(arg->argLongForm));
  1023.     if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
  1024.     {
  1025.     if (!rt->rtSimpleCheckReply)
  1026.         fprintf(file, "\t    (MACH_MSG_TYPE_PORT_ANY(OutP->%s.msgt%s_name) && msgh_simple) ||\n",
  1027.             arg->argTTName,
  1028.             arg->argLongForm ? "l" : "");
  1029.     }
  1030.     else
  1031.     fprintf(file, "\t    (OutP->%s.msgt%s_name != %s) ||\n",
  1032.         arg->argTTName,
  1033.         arg->argLongForm ? "l" : "",
  1034.         it->itOutNameStr);
  1035.     if (!it->itVarArray)
  1036.     fprintf(file, "\t    (OutP->%s.msgt%s_number != %d) ||\n",
  1037.         arg->argTTName,
  1038.         arg->argLongForm ? "l" : "",
  1039.         it->itNumber);
  1040.     fprintf(file, "\t    (OutP->%s.msgt%s_size != %d))\n",
  1041.         arg->argTTName,
  1042.         arg->argLongForm ? "l" : "",
  1043.         it->itSize);
  1044.     if (akCheck(arg->argKind, akbReplyQC))
  1045.     fprintf(file, "#endif\tUseStaticMsgType\n");
  1046.     WriteMsgError(file, rt, "MIG_TYPE_ERROR");
  1047.     fprintf(file, "#endif\tTypeCheck\n");
  1048.     fprintf(file, "\n");
  1049. }
  1050.  
  1051. static void
  1052. WriteCheckArgSize(file, arg)
  1053.     FILE *file;
  1054.     register argument_t *arg;
  1055. {
  1056.     register ipc_type_t *ptype = arg->argType;
  1057.     register ipc_type_t *btype = ptype->itElement;
  1058.     argument_t *count = arg->argCount;
  1059.     int multiplier = btype->itTypeSize / btype->itNumber;
  1060.  
  1061.     if (ptype->itIndefinite) {
  1062.     /*
  1063.      * Check descriptor.  If out-of-line, use standard size.
  1064.      */
  1065.     fprintf(file, "(OutP->%s%s.msgt_inline) ? ",
  1066.         arg->argTTName, arg->argLongForm ? ".msgtl_header" : "");
  1067.     }
  1068.  
  1069.     if (multiplier > 1)
  1070.     fprintf(file, "%d * ", multiplier);
  1071.  
  1072.     fprintf(file, "OutP->%s", count->argMsgField);
  1073.  
  1074.     /* If the base type size of the data field isn`t a multiple of 4,
  1075.        we have to round up. */
  1076.     if (btype->itTypeSize % 4 != 0)
  1077.     fprintf(file, " + 3 & ~3");
  1078.  
  1079.     if (ptype->itIndefinite)
  1080.     fprintf(file, " : sizeof(%s *)", FetchUserType(btype));
  1081. }
  1082.  
  1083. static void
  1084. WriteCheckMsgSize(file, arg)
  1085.     FILE *file;
  1086.     register argument_t *arg;
  1087. {
  1088.     register routine_t *rt = arg->argRoutine;
  1089.  
  1090.     /* If there aren't any more Out args after this, then
  1091.        we can use the msgh_size_delta value directly in
  1092.        the TypeCheck conditional. */
  1093.  
  1094.     if (arg->argReplyPos == rt->rtMaxReplyPos)
  1095.     {
  1096.     fprintf(file, "#if\tTypeCheck\n");
  1097.     fprintf(file, "\tif (msgh_size != %d + (",
  1098.         rt->rtReplySize);
  1099.     WriteCheckArgSize(file, arg);
  1100.     fprintf(file, "))\n");
  1101.  
  1102.     WriteMsgError(file, rt, "MIG_TYPE_ERROR");
  1103.     fprintf(file, "#endif\tTypeCheck\n");
  1104.     }
  1105.     else
  1106.     {
  1107.     /* If there aren't any more variable-sized arguments after this,
  1108.        then we must check for exact msg-size and we don't need
  1109.        to update msgh_size. */
  1110.  
  1111.     boolean_t LastVarArg = arg->argReplyPos+1 == rt->rtNumReplyVar;
  1112.  
  1113.     /* calculate the actual size in bytes of the data field.  note
  1114.        that this quantity must be a multiple of four.  hence, if
  1115.        the base type size isn't a multiple of four, we have to
  1116.        round up.  note also that btype->itNumber must
  1117.        divide btype->itTypeSize (see itCalculateSizeInfo). */
  1118.  
  1119.     fprintf(file, "\tmsgh_size_delta = ");
  1120.     WriteCheckArgSize(file, arg);
  1121.     fprintf(file, ";\n");
  1122.     fprintf(file, "#if\tTypeCheck\n");
  1123.  
  1124.     /* Don't decrement msgh_size until we've checked that
  1125.        it won't underflow. */
  1126.  
  1127.     if (LastVarArg)
  1128.         fprintf(file, "\tif (msgh_size != %d + msgh_size_delta)\n",
  1129.         rt->rtReplySize);
  1130.     else
  1131.         fprintf(file, "\tif (msgh_size < %d + msgh_size_delta)\n",
  1132.         rt->rtReplySize);
  1133.     WriteMsgError(file, rt, "MIG_TYPE_ERROR");
  1134.  
  1135.     if (!LastVarArg)
  1136.         fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
  1137.  
  1138.     fprintf(file, "#endif\tTypeCheck\n");
  1139.     }
  1140.     fprintf(file, "\n");
  1141. }
  1142.  
  1143. /*************************************************************
  1144.  *  Write code to copy an argument from the reply message
  1145.  *  to the parameter. Called by WriteRoutine for each argument
  1146.  *  in the reply message.
  1147.  *************************************************************/
  1148. static void
  1149. WriteExtractArgValue(file, arg)
  1150.     FILE *file;
  1151.     register argument_t *arg;
  1152. {
  1153.     register ipc_type_t    *argType = arg->argType;
  1154.     register char *ref = arg->argByReferenceUser ? "*" : "";
  1155.  
  1156.     if (argType->itInLine && argType->itVarArray) {
  1157.  
  1158.     if (argType->itString) {
  1159.         /*
  1160.          *    Copy out variable-size C string with mig_strncpy.
  1161.          */
  1162.         fprintf(file, "\t(void) mig_strncpy(%s%s, OutP->%s, %d);\n",
  1163.         ref,
  1164.         arg->argVarName,
  1165.         arg->argMsgField,
  1166.         argType->itNumber);
  1167.     }
  1168.     else if (argType->itIndefinite) {
  1169.         /*
  1170.          * If data was returned out-of-line,
  1171.          *    change user`s pointer to point to it.
  1172.          * If data was returned in-line but doesn`t fit,
  1173.          *    allocate a new buffer, copy the data to it,
  1174.          *      and change user`s pointer to point to it.
  1175.          * If data was returned in-line and fits,
  1176.          *    copy to buffer.
  1177.          */
  1178.         argument_t *count = arg->argCount;
  1179.         char *countRef = count->argByReferenceUser ? "*" : "";
  1180.         ipc_type_t *btype = argType->itElement;
  1181.  
  1182.         fprintf(file, "\tif (!OutP->%s%s.msgt_inline)\n",
  1183.             arg->argTTName,
  1184.             arg->argLongForm ? ".msgtl_header" : "");
  1185.         fprintf(file, "\t    %s%s = *((%s **)OutP->%s);\n",
  1186.             ref, arg->argVarName,
  1187.             FetchUserType(btype), arg->argMsgField);
  1188.         fprintf(file, "\telse if (OutP->%s",
  1189.             count->argMsgField);
  1190.         if (btype->itNumber > 1)
  1191.         fprintf(file, " / %d",
  1192.             btype->itNumber);
  1193.         fprintf(file, " > %s%s) {\n",
  1194.             countRef, count->argVarName);
  1195.         fprintf(file, "\t    mig_allocate((vm_offset_t *)%s,\n\t\t",
  1196.             arg->argVarName);    /* no ref! */
  1197.         if (btype->itTypeSize != btype->itNumber)
  1198.         fprintf(file, "%d * ",
  1199.             btype->itTypeSize/btype->itNumber);
  1200.         fprintf(file, "OutP->%s);\n",
  1201.             count->argMsgField);
  1202.         fprintf(file, "\t    bcopy((char *) OutP->%s, (char *) %s%s, ",
  1203.             arg->argMsgField,
  1204.             ref, arg->argVarName);
  1205.         if (btype->itTypeSize != btype->itNumber)
  1206.         fprintf(file, "%d * ",
  1207.             btype->itTypeSize/btype->itNumber);
  1208.         fprintf(file, "OutP->%s);\n",
  1209.             count->argMsgField);
  1210.         fprintf(file, "\t}\n");
  1211.         fprintf(file, "\telse {\n");
  1212.  
  1213.         fprintf(file, "\t    bcopy((char *) OutP->%s, (char *) %s%s, ",
  1214.             arg->argMsgField,
  1215.             ref, arg->argVarName);
  1216.         if (btype->itTypeSize != btype->itNumber)
  1217.         fprintf(file, "%d * ",
  1218.             btype->itTypeSize/btype->itNumber);
  1219.         fprintf(file, "OutP->%s);\n",
  1220.         count->argMsgField);
  1221.         fprintf(file, "\t}\n");
  1222.     }
  1223.     else {
  1224.  
  1225.         /*
  1226.          *    Copy out variable-size inline array with bcopy,
  1227.          *    after checking that number of elements doesn`t
  1228.          *    exceed user`s maximum.
  1229.          */
  1230.         register argument_t *count = arg->argCount;
  1231.         register char *countRef = count->argByReferenceUser ? "*" : "";
  1232.         register ipc_type_t *btype = argType->itElement;
  1233.  
  1234.         /* Note count->argMultiplier == btype->itNumber */
  1235.  
  1236.         fprintf(file, "\tif (OutP->%s", count->argMsgField);
  1237.         if (btype->itNumber > 1)
  1238.         fprintf(file, " / %d", btype->itNumber);
  1239.         fprintf(file, " > %s%s) {\n",
  1240.         countRef, count->argVarName);
  1241.  
  1242.         /*
  1243.          * If number of elements is too many for user receiving area,
  1244.          * fill user`s area as much as possible.  Return the correct
  1245.          * number of elements.
  1246.          */
  1247.         fprintf(file, "\t\tbcopy((char *) OutP->%s, (char *) %s%s, ",
  1248.         arg->argMsgField, ref, arg->argVarName);
  1249.         if (btype->itTypeSize > 1)
  1250.         fprintf(file, "%d * ", btype->itTypeSize);
  1251.         fprintf(file, "%s%s);\n",
  1252.         countRef, count->argVarName);
  1253.  
  1254.         fprintf(file, "\t\t%s%s = OutP->%s",
  1255.              countRef, count->argVarName, count->argMsgField);
  1256.         if (btype->itNumber > 1)
  1257.         fprintf(file, " / %d", btype->itNumber);
  1258.         fprintf(file, ";\n");
  1259.         WriteMsgError(file,arg->argRoutine, "MIG_ARRAY_TOO_LARGE");
  1260.  
  1261.         fprintf(file, "\t}\n\telse {\n");
  1262.  
  1263.         fprintf(file, "\t\tbcopy((char *) OutP->%s, (char *) %s%s, ",
  1264.         arg->argMsgField, ref, arg->argVarName);
  1265.         if (btype->itTypeSize != btype->itNumber)
  1266.         fprintf(file, "%d * ",
  1267.             btype->itTypeSize/btype->itNumber);
  1268.         fprintf(file, "OutP->%s);\n",
  1269.         count->argMsgField);
  1270.         fprintf(file, "\t}\n");
  1271.     }
  1272.     }
  1273.     else if (arg->argMultiplier > 1)
  1274.     WriteCopyType(file, argType,
  1275.               "%s%s", "/* %s%s */ OutP->%s / %d",
  1276.               ref, arg->argVarName, arg->argMsgField,
  1277.               arg->argMultiplier);
  1278.     else
  1279.     WriteCopyType(file, argType,
  1280.               "%s%s", "/* %s%s */ OutP->%s",
  1281.               ref, arg->argVarName, arg->argMsgField);
  1282.     fprintf(file, "\n");
  1283. }
  1284.  
  1285. static void
  1286. WriteExtractArg(file, arg)
  1287.     FILE *file;
  1288.     register argument_t *arg;
  1289. {
  1290.     register routine_t *rt = arg->argRoutine;
  1291.  
  1292.     if (akCheck(arg->argKind, akbReply))
  1293.     WriteTypeCheck(file, arg);
  1294.  
  1295.     if (akCheckAll(arg->argKind, akbVariable|akbReply))
  1296.     WriteCheckMsgSize(file, arg);
  1297.  
  1298.     /* Now that the RetCode is type-checked, check its value.
  1299.        Must abort immediately if it isn't KERN_SUCCESS, because
  1300.        in that case the reply message is truncated. */
  1301.  
  1302.     if (arg == rt->rtRetCode)
  1303.     WriteRetCodeCheck(file, rt);
  1304.  
  1305.     if (akCheckAll(arg->argKind, akbReturnRcv))
  1306.     WriteExtractArgValue(file, arg);
  1307. }
  1308.  
  1309. WriteAdjustReplyMsgPtr(file, arg)
  1310.     FILE *file;
  1311.     register argument_t *arg;
  1312. {
  1313.     register ipc_type_t *ptype = arg->argType;
  1314.  
  1315.     fprintf(file,
  1316.     "\tOutP = (Reply *) ((char *) OutP + msgh_size_delta - %d);\n\n",
  1317.     ptype->itTypeSize + ptype->itPadSize);
  1318. }
  1319.  
  1320. void
  1321. WriteReplyArgs(file, rt)
  1322.     FILE *file;
  1323.     register routine_t *rt;
  1324. {
  1325.     register argument_t *arg;
  1326.     register argument_t *lastVarArg;
  1327.  
  1328.     lastVarArg = argNULL;
  1329.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
  1330.  
  1331.     /*
  1332.      * Advance message pointer if the last reply argument was
  1333.      * variable-length and the reply position will change.
  1334.      */
  1335.     if (lastVarArg != argNULL &&
  1336.         lastVarArg->argReplyPos < arg->argReplyPos)
  1337.     {
  1338.         WriteAdjustReplyMsgPtr(file, lastVarArg);
  1339.         lastVarArg = argNULL;
  1340.     }
  1341.  
  1342.     /*
  1343.      * Copy the argument
  1344.      */
  1345.     WriteExtractArg(file, arg);
  1346.  
  1347.     /*
  1348.      * Remember whether this was variable-length.
  1349.      */
  1350.     if (akCheckAll(arg->argKind, akbReturnRcv|akbVariable))
  1351.         lastVarArg = arg;
  1352.     }
  1353. }
  1354.  
  1355. /*************************************************************
  1356.  *  Writes code to return the return value. Called by WriteRoutine
  1357.  *  for routines and functions.
  1358.  *************************************************************/
  1359. static void
  1360. WriteReturnValue(file, rt)
  1361.     FILE *file;
  1362.     routine_t *rt;
  1363. {
  1364.     if (rt->rtReturn == rt->rtRetCode)
  1365.     /* If returning RetCode, we have already checked that it is
  1366.        KERN_SUCCESS */
  1367.     fprintf(file, "\treturn KERN_SUCCESS;\n");
  1368.  
  1369.     else
  1370.     {
  1371.     if (rt->rtNumReplyVar > 0)
  1372.         fprintf(file, "\tOutP = &Mess.Out;\n");
  1373.  
  1374.     fprintf(file, "\treturn OutP->%s;\n", rt->rtReturn->argMsgField);
  1375.     }
  1376. }
  1377.  
  1378. /*************************************************************
  1379.  *  Writes the elements of the message type declaration: the
  1380.  *  msg_type structure, the argument itself and any padding 
  1381.  *  that is required to make the argument a multiple of 4 bytes.
  1382.  *  Called by WriteRoutine for all the arguments in the request
  1383.  *  message first and then the reply message.
  1384.  *************************************************************/
  1385. static void
  1386. WriteFieldDecl(file, arg)
  1387.     FILE *file;
  1388.     argument_t *arg;
  1389. {
  1390.     WriteFieldDeclPrim(file, arg, FetchUserType);
  1391. }
  1392.  
  1393. static void
  1394. WriteStubDecl(file, rt)
  1395.     FILE *file;
  1396.     register routine_t *rt;
  1397. {
  1398.     fprintf(file, "\n");
  1399.     fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
  1400.     fprintf(file, "mig_external %s %s\n", ReturnTypeStr(rt), rt->rtUserName);
  1401.     fprintf(file, "#if\t%s\n", NewCDecl);
  1402.     fprintf(file, "(\n");
  1403.     WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
  1404.     fprintf(file, ")\n");
  1405.     fprintf(file, "#else\n");
  1406.     fprintf(file, "\t(");
  1407.     WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", ", "");
  1408.     fprintf(file, ")\n");
  1409.     WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ";\n", ";\n");
  1410.     fprintf(file, "#endif\n");
  1411.     fprintf(file, "{\n");
  1412. }
  1413.  
  1414. /*************************************************************
  1415.  *  Writes all the code comprising a routine body. Called by
  1416.  *  WriteUser for each routine.
  1417.  *************************************************************/
  1418. static void
  1419. WriteRoutine(file, rt)
  1420.     FILE *file;
  1421.     register routine_t *rt;
  1422. {
  1423.     /* write the stub's declaration */
  1424.  
  1425.     WriteStubDecl(file, rt);
  1426.  
  1427.     /* typedef of structure for Request and Reply messages */
  1428.  
  1429.     WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request");
  1430.     if (!rt->rtOneWay)
  1431.     WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply");
  1432.  
  1433.     /* declarations for local vars: Union of Request and Reply messages,
  1434.        InP, OutP and return value */
  1435.  
  1436.     WriteVarDecls(file, rt);
  1437.  
  1438.     /* declarations and initializations of the mach_msg_type_t variables
  1439.        for each argument */
  1440.  
  1441.     WriteList(file, rt->rtArgs, WriteTypeDeclIn, akbRequest, "\n", "\n");
  1442.     if (!rt->rtOneWay)
  1443.     WriteList(file, rt->rtArgs, WriteCheckDecl, akbReplyQC, "\n", "\n");
  1444.  
  1445.     /* fill in all the request message types and then arguments */
  1446.  
  1447.     WriteRequestArgs(file, rt);
  1448.  
  1449.     /* fill in request message head */
  1450.  
  1451.     WriteRequestHead(file, rt);
  1452.     fprintf(file, "\n");
  1453.  
  1454.     /* Write the send/receive or rpc call */
  1455.  
  1456.     if (rt->rtOneWay)
  1457.     WriteMsgSend(file, rt);
  1458.     else
  1459.     {
  1460.     if (UseMsgRPC)
  1461.         WriteMsgRPC(file, rt);
  1462.     else
  1463.         WriteMsgSendReceive(file, rt);
  1464.  
  1465.     /* Check the values that are returned in the reply message */
  1466.  
  1467.     WriteCheckIdentity(file, rt);
  1468.  
  1469.     /* If the reply message has no Out parameters or return values
  1470.        other than the return code, we can type-check it and
  1471.        return it directly. */
  1472.  
  1473.     if (rt->rtNoReplyArgs)
  1474.     {
  1475.         WriteTypeCheck(file, rt->rtRetCode);
  1476.  
  1477.         fprintf(file, "\treturn OutP->RetCode;\n");
  1478.     }
  1479.     else {
  1480.         WriteReplyArgs(file, rt);
  1481.  
  1482.         /* return the return value, if any */
  1483.  
  1484.         if (rt->rtProcedure)
  1485.         fprintf(file, "\t/* Procedure - no return needed */\n");
  1486.         else
  1487.         WriteReturnValue(file, rt);
  1488.     }
  1489.     }
  1490.  
  1491.     fprintf(file, "}\n");
  1492. }
  1493.  
  1494. /*************************************************************
  1495.  *  Writes out the xxxUser.c file. Called by mig.c
  1496.  *************************************************************/
  1497. void
  1498. WriteUser(file, stats)
  1499.     FILE *file;
  1500.     statement_t *stats;
  1501. {
  1502.     register statement_t *stat;
  1503.  
  1504.     WriteProlog(file);
  1505.     for (stat = stats; stat != stNULL; stat = stat->stNext)
  1506.     switch (stat->stKind)
  1507.     {
  1508.       case skRoutine:
  1509.         WriteRoutine(file, stat->stRoutine);
  1510.         break;
  1511.       case skImport:
  1512.       case skUImport:
  1513.       case skSImport:
  1514.         break;
  1515.       default:
  1516.         fatal("WriteUser(): bad statement_kind_t (%d)",
  1517.           (int) stat->stKind);
  1518.     }
  1519.     WriteEpilog(file);
  1520. }
  1521.  
  1522. /*************************************************************
  1523.  *  Writes out individual .c user files for each routine.  Called by mig.c
  1524.  *************************************************************/
  1525. void
  1526. WriteUserIndividual(stats)
  1527.     statement_t *stats;
  1528. {
  1529.     register statement_t *stat;
  1530.  
  1531.     for (stat = stats; stat != stNULL; stat = stat->stNext)
  1532.     switch (stat->stKind)
  1533.     {
  1534.       case skRoutine:
  1535.         {
  1536.         FILE *file;
  1537.         register char *filename;
  1538.  
  1539.         filename = strconcat(UserFilePrefix,
  1540.                      strconcat(stat->stRoutine->rtName, ".c"));
  1541.         file = fopen(filename, "w");
  1542.         if (file == NULL)
  1543.             fatal("fopen(%s): %s", filename,
  1544.               unix_error_string(errno));
  1545.         WriteProlog(file);
  1546.         WriteRoutine(file, stat->stRoutine);
  1547.         WriteEpilog(file);
  1548.         fclose(file);
  1549.         strfree(filename);
  1550.         }
  1551.         break;
  1552.       case skImport:
  1553.       case skUImport:
  1554.       case skSImport:
  1555.         break;
  1556.       default:
  1557.         fatal("WriteUserIndividual(): bad statement_kind_t (%d)",
  1558.           (int) stat->stKind);
  1559.     }
  1560. }
  1561.